#pragma once

#include "util.hpp"
#include "message.hpp"
#include "format.hpp"
#include <memory>
#include <fstream>
#include <ctime>

class LogSink
{
public:
    using ptr = std::shared_ptr<LogSink>;
    LogSink()
    {
    }
    virtual ~LogSink()
    {
    }
    virtual void log(const char *data, size_t len) = 0;
};

// 标准输出
class StdoutSink : public LogSink
{
public:
    using ptr = std::shared_ptr<StdoutSink>;
    StdoutSink() = default; // 告诉编译器 使用默认构造函数的默认实现
    void log(const char *data, size_t len) override
    {
        std::cout.write(data, len);
    }
};

// 指定文件输出
class FileSink : public LogSink
{
public:
    using ptr = std::shared_ptr<FileSink>;
    FileSink(const std::string &filename) : _filename(filename)
    {
        util::file::CreateDirectory(filename);
        _ofs.open(_filename, std::ios::binary | std::ios::app);
        assert(_ofs.is_open());
    }

    const std::string &file()
    {
        return _filename;
    }

    void log(const char *data, size_t len) override
    {
        _ofs.write((const char *)data, len);
        if (_ofs.good() == false)
        {
            std::cout << "日志文件输出失败\n";
        }
    }

private:
    std::string _filename;
    std::ofstream _ofs;
};

// 滚动文件输出
class RollSink : public LogSink
{
public:
    using ptr = std::shared_ptr<RollSink>;
    RollSink(const std::string &basename, size_t max_fsize) : _basename(basename), _max_fsize(max_fsize), _cur_fsize(0)
    {
        util::file::CreateDirectory(basename);
    }

    void log(const char *data, size_t len) override
    {
        // 每次写入日志都会调用日志初始化函数
        initLogFile();
        _ofs.write(data, len);
        if (_ofs.good() == false)
        {
            std::cout << "日志输出文件失败！\n";
        }
        _cur_fsize += len;
    }

private:
    void initLogFile()
    {
        if (_ofs.is_open() == false || _cur_fsize >= _max_fsize)
        {
            _ofs.close();
            std::string name = createFilename();
            _ofs.open(name, std::ios::binary | std::ios::app);
            assert(_ofs.is_open());
            _cur_fsize = 0;
            return;
        }
        return;
    }

    std::string createFilename()
    {
        time_t t = time(nullptr);
        struct tm lt;
        localtime_r(&t, &lt);
        std::stringstream ss;
        ss << _basename;
        ss << lt.tm_year + 1900;
        ss << lt.tm_mon + 1;
        ss << lt.tm_mday;
        ss << lt.tm_hour;
        ss << lt.tm_min;
        ss << lt.tm_sec;
        ss << ".log";
        return ss.str();
    }

private:
    std::string _basename; // 文件基础名
    std::ofstream _ofs;
    size_t _max_fsize; // 文件最大大小
    size_t _cur_fsize; // 当前文件大小
};

// 定义工厂类：创建 LogSink 类型的对象
class SinkFactory
{
public:
    template <typename SinkType, typename... Args>
    static LogSink::ptr create(Args &&...args)
    {
        return std::make_shared<SinkType>(std::forward<Args>(args)...);
    }
};
